<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title id="head-title">report.html</title>
      <style type="text/css">body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
  /* do not increase min-width as some may use split screens */
  min-width: 800px;
  color: #999;
}

h1 {
  font-size: 24px;
  color: black;
}

h2 {
  font-size: 16px;
  color: black;
}

p {
  color: black;
}

a {
  color: #999;
}

table {
  border-collapse: collapse;
}

/******************************
 * SUMMARY INFORMATION
 ******************************/
#environment td {
  padding: 5px;
  border: 1px solid #e6e6e6;
  vertical-align: top;
}
#environment tr:nth-child(odd) {
  background-color: #f6f6f6;
}
#environment ul {
  margin: 0;
  padding: 0 20px;
}

/******************************
 * TEST RESULT COLORS
 ******************************/
span.passed,
.passed .col-result {
  color: green;
}

span.skipped,
span.xfailed,
span.rerun,
.skipped .col-result,
.xfailed .col-result,
.rerun .col-result {
  color: orange;
}

span.error,
span.failed,
span.xpassed,
.error .col-result,
.failed .col-result,
.xpassed .col-result {
  color: red;
}

.col-links__extra {
  margin-right: 3px;
}

/******************************
 * RESULTS TABLE
 *
 * 1. Table Layout
 * 2. Extra
 * 3. Sorting items
 *
 ******************************/
/*------------------
 * 1. Table Layout
 *------------------*/
#results-table {
  border: 1px solid #e6e6e6;
  color: #999;
  font-size: 12px;
  width: 100%;
}
#results-table th,
#results-table td {
  padding: 5px;
  border: 1px solid #e6e6e6;
  text-align: left;
}
#results-table th {
  font-weight: bold;
}

/*------------------
 * 2. Extra
 *------------------*/
.logwrapper {
  max-height: 230px;
  overflow-y: scroll;
  background-color: #e6e6e6;
}
.logwrapper.expanded {
  max-height: none;
}
.logwrapper.expanded .logexpander:after {
  content: "collapse [-]";
}
.logwrapper .logexpander {
  z-index: 1;
  position: sticky;
  top: 10px;
  width: max-content;
  border: 1px solid;
  border-radius: 3px;
  padding: 5px 7px;
  margin: 10px 0 10px calc(100% - 80px);
  cursor: pointer;
  background-color: #e6e6e6;
}
.logwrapper .logexpander:after {
  content: "expand [+]";
}
.logwrapper .logexpander:hover {
  color: #000;
  border-color: #000;
}
.logwrapper .log {
  min-height: 40px;
  position: relative;
  top: -50px;
  height: calc(100% + 50px);
  border: 1px solid #e6e6e6;
  color: black;
  display: block;
  font-family: "Courier New", Courier, monospace;
  padding: 5px;
  padding-right: 80px;
  white-space: pre-wrap;
}

div.media {
  border: 1px solid #e6e6e6;
  float: right;
  height: 240px;
  margin: 0 5px;
  overflow: hidden;
  width: 320px;
}

.media-container {
  display: grid;
  grid-template-columns: 25px auto 25px;
  align-items: center;
  flex: 1 1;
  overflow: hidden;
  height: 200px;
}

.media-container--fullscreen {
  grid-template-columns: 0px auto 0px;
}

.media-container__nav--right,
.media-container__nav--left {
  text-align: center;
  cursor: pointer;
}

.media-container__viewport {
  cursor: pointer;
  text-align: center;
  height: inherit;
}
.media-container__viewport img,
.media-container__viewport video {
  object-fit: cover;
  width: 100%;
  max-height: 100%;
}

.media__name,
.media__counter {
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  flex: 0 0 25px;
  align-items: center;
}

.collapsible td:not(.col-links) {
  cursor: pointer;
}
.collapsible td:not(.col-links):hover::after {
  color: #bbb;
  font-style: italic;
  cursor: pointer;
}

.col-result {
  width: 130px;
}
.col-result:hover::after {
  content: " (hide details)";
}

.col-result.collapsed:hover::after {
  content: " (show details)";
}

#environment-header h2:hover::after {
  content: " (hide details)";
  color: #bbb;
  font-style: italic;
  cursor: pointer;
  font-size: 12px;
}

#environment-header.collapsed h2:hover::after {
  content: " (show details)";
  color: #bbb;
  font-style: italic;
  cursor: pointer;
  font-size: 12px;
}

/*------------------
 * 3. Sorting items
 *------------------*/
.sortable {
  cursor: pointer;
}
.sortable.desc:after {
  content: " ";
  position: relative;
  left: 5px;
  bottom: -12.5px;
  border: 10px solid #4caf50;
  border-bottom: 0;
  border-left-color: transparent;
  border-right-color: transparent;
}
.sortable.asc:after {
  content: " ";
  position: relative;
  left: 5px;
  bottom: 12.5px;
  border: 10px solid #4caf50;
  border-top: 0;
  border-left-color: transparent;
  border-right-color: transparent;
}

.hidden, .summary__reload__button.hidden {
  display: none;
}

.summary__data {
  flex: 0 0 550px;
}
.summary__reload {
  flex: 1 1;
  display: flex;
  justify-content: center;
}
.summary__reload__button {
  flex: 0 0 300px;
  display: flex;
  color: white;
  font-weight: bold;
  background-color: #4caf50;
  text-align: center;
  justify-content: center;
  align-items: center;
  border-radius: 3px;
  cursor: pointer;
}
.summary__reload__button:hover {
  background-color: #46a049;
}
.summary__spacer {
  flex: 0 0 550px;
}

.controls {
  display: flex;
  justify-content: space-between;
}

.filters,
.collapse {
  display: flex;
  align-items: center;
}
.filters button,
.collapse button {
  color: #999;
  border: none;
  background: none;
  cursor: pointer;
  text-decoration: underline;
}
.filters button:hover,
.collapse button:hover {
  color: #ccc;
}

.filter__label {
  margin-right: 10px;
}

      </style>
    
  </head>
  <body>
    <h1 id="title">report.html</h1>
    <p>Report generated on 05-Nov-2025 at 16:27:11 by <a href="https://pypi.python.org/pypi/pytest-html">pytest-html</a>
        v4.1.1</p>
    <div id="environment-header">
      <h2>Environment</h2>
    </div>
    <table id="environment"></table>
    <!-- TEMPLATES -->
      <template id="template_environment_row">
      <tr>
        <td></td>
        <td></td>
      </tr>
    </template>
    <template id="template_results-table__body--empty">
      <tbody class="results-table-row">
        <tr id="not-found-message">
          <td colspan="4">No results found. Check the filters.</th>
        </tr>
    </template>
    <template id="template_results-table__tbody">
      <tbody class="results-table-row">
        <tr class="collapsible">
        </tr>
        <tr class="extras-row">
          <td class="extra" colspan="4">
            <div class="extraHTML"></div>
            <div class="media">
              <div class="media-container">
                  <div class="media-container__nav--left"><</div>
                  <div class="media-container__viewport">
                    <img src="" />
                    <video controls>
                      <source src="" type="video/mp4">
                    </video>
                  </div>
                  <div class="media-container__nav--right">></div>
                </div>
                <div class="media__name"></div>
                <div class="media__counter"></div>
            </div>
            <div class="logwrapper">
              <div class="logexpander"></div>
              <div class="log"></div>
            </div>
          </td>
        </tr>
      </tbody>
    </template>
    <!-- END TEMPLATES -->
    <div class="summary">
      <div class="summary__data">
        <h2>Summary</h2>
        <div class="additional-summary prefix">
        </div>
        <p class="run-count">11 tests took 41 ms.</p>
        <p class="filter">(Un)check the boxes to filter the results.</p>
        <div class="summary__reload">
          <div class="summary__reload__button hidden" onclick="location.reload()">
            <div>There are still tests running. <br />Reload this page to get the latest results!</div>
          </div>
        </div>
        <div class="summary__spacer"></div>
        <div class="controls">
          <div class="filters">
            <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="failed" />
            <span class="failed">2 Failed,</span>
            <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="passed" />
            <span class="passed">9 Passed,</span>
            <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="skipped" disabled/>
            <span class="skipped">0 Skipped,</span>
            <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="xfailed" disabled/>
            <span class="xfailed">0 Expected failures,</span>
            <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="xpassed" disabled/>
            <span class="xpassed">0 Unexpected passes,</span>
            <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="error" disabled/>
            <span class="error">0 Errors,</span>
            <input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="rerun" disabled/>
            <span class="rerun">0 Reruns</span>
          </div>
          <div class="collapse">
            <button id="show_all_details">Show all details</button>&nbsp;/&nbsp;<button id="hide_all_details">Hide all details</button>
          </div>
        </div>
      </div>
      <div class="additional-summary summary">
      </div>
      <div class="additional-summary postfix">
      </div>
    </div>
    <table id="results-table">
      <thead id="results-table-head">
        <tr>
          <th class="sortable" data-column-type="result">Result</th>
          <th class="sortable" data-column-type="testId">Test</th>
          <th class="sortable" data-column-type="duration">Duration</th>
          <th>Links</th>
        </tr>
      </thead>
    </table>
  </body>
  <footer>
    <div id="data-container" data-jsonblob="{&#34;environment&#34;: {&#34;Python&#34;: &#34;3.9.1&#34;, &#34;Platform&#34;: &#34;macOS-15.4.1-arm64-arm-64bit&#34;, &#34;Packages&#34;: {&#34;pytest&#34;: &#34;8.3.5&#34;, &#34;pluggy&#34;: &#34;1.6.0&#34;}, &#34;Plugins&#34;: {&#34;allure-pytest&#34;: &#34;2.14.3&#34;, &#34;html&#34;: &#34;4.1.1&#34;, &#34;metadata&#34;: &#34;3.1.1&#34;}, &#34;CI&#34;: &#34;true&#34;, &#34;BUILD_NUMBER&#34;: &#34;21&#34;, &#34;BUILD_ID&#34;: &#34;21&#34;, &#34;BUILD_URL&#34;: &#34;http://127.0.0.1:8080/job/bysms-%E6%B5%81%E6%B0%B4%E7%BA%BF%E5%BD%A2%E5%BC%8F-%E9%87%8D%E8%A6%81/21/&#34;, &#34;NODE_NAME&#34;: &#34;built-in&#34;, &#34;JOB_NAME&#34;: &#34;bysms-\u6d41\u6c34\u7ebf\u5f62\u5f0f-\u91cd\u8981&#34;, &#34;BUILD_TAG&#34;: &#34;jenkins-bysms-\u6d41\u6c34\u7ebf\u5f62\u5f0f-\u91cd\u8981-21&#34;, &#34;EXECUTOR_NUMBER&#34;: &#34;1&#34;, &#34;JENKINS_URL&#34;: &#34;http://127.0.0.1:8080/&#34;, &#34;JAVA_HOME&#34;: &#34;/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home&#34;, &#34;WORKSPACE&#34;: &#34;/Users/show/.jenkins/workspace/bysms-\u6d41\u6c34\u7ebf\u5f62\u5f0f-\u91cd\u8981&#34;}, &#34;tests&#34;: {&#34;case/login_test.py::Test_api0001_0004::test_api_0001_0005[byhy-88888888-0-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api0001_0004::test_api_0001_0005[byhy-88888888-0-None]&#34;, &#34;duration&#34;: &#34;10 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api0001_0004::test_api_0001_0005[byhy-88888888-0-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;10 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;---------------------------- Captured stdout setup -----------------------------\n{&amp;#x27;login_requests&amp;#x27;: {&amp;#x27;method&amp;#x27;: &amp;#x27;post&amp;#x27;, &amp;#x27;url&amp;#x27;: &amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;, &amp;#x27;data&amp;#x27;: {&amp;#x27;username&amp;#x27;: &amp;#x27;${username}&amp;#x27;, &amp;#x27;password&amp;#x27;: &amp;#x27;${password}&amp;#x27;}}, &amp;#x27;list_medicine&amp;#x27;: {&amp;#x27;method&amp;#x27;: &amp;#x27;get&amp;#x27;, &amp;#x27;url&amp;#x27;: &amp;#x27;http://127.0.0.1/api/mgr/medicines&amp;#x27;, &amp;#x27;params&amp;#x27;: {&amp;#x27;action&amp;#x27;: &amp;#x27;list_medicine&amp;#x27;, &amp;#x27;pagesize&amp;#x27;: &amp;#x27;${pagesize}&amp;#x27;, &amp;#x27;pagenum&amp;#x27;: &amp;#x27;${pagenum}&amp;#x27;}}}\n\n----------------------------- Captured stdout call -----------------------------\n\u5728login_requests\u91cc\u9762\u6253\u5370\u4e86\uff1a{&amp;#x27;username&amp;#x27;: &amp;#x27;byhy&amp;#x27;, &amp;#x27;password&amp;#x27;: 88888888}\n\u5728cases\u91cc\u9762\uff1ars_code:200,rs_ret:0,rs_msg:None\n&#34;}], &#34;case/login_test.py::Test_api0001_0004::test_api_0001_0005[byhy-8888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api0001_0004::test_api_0001_0005[byhy-8888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;, &#34;duration&#34;: &#34;3 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api0001_0004::test_api_0001_0005[byhy-8888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;3 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;----------------------------- Captured stdout call -----------------------------\n\u5728login_requests\u91cc\u9762\u6253\u5370\u4e86\uff1a{&amp;#x27;username&amp;#x27;: &amp;#x27;byhy&amp;#x27;, &amp;#x27;password&amp;#x27;: 8888}\n\u5728cases\u91cc\u9762\uff1ars_code:200,rs_ret:1,rs_msg:\u7528\u6237\u540d\u6216\u8005\u5bc6\u7801\u9519\u8bef\n&#34;}], &#34;case/login_test.py::Test_api0001_0004::test_api_0001_0005[None-88888888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api0001_0004::test_api_0001_0005[None-88888888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;, &#34;duration&#34;: &#34;3 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api0001_0004::test_api_0001_0005[None-88888888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;3 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;----------------------------- Captured stdout call -----------------------------\n\u5728login_requests\u91cc\u9762\u6253\u5370\u4e86\uff1a{&amp;#x27;username&amp;#x27;: &amp;#x27;None&amp;#x27;, &amp;#x27;password&amp;#x27;: 88888888}\n\u5728cases\u91cc\u9762\uff1ars_code:200,rs_ret:1,rs_msg:\u7528\u6237\u540d\u6216\u8005\u5bc6\u7801\u9519\u8bef\n&#34;}], &#34;case/login_test.py::Test_api0001_0004::test_api_0001_0005[byhy-None-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api0001_0004::test_api_0001_0005[byhy-None-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;, &#34;duration&#34;: &#34;3 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api0001_0004::test_api_0001_0005[byhy-None-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;3 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;----------------------------- Captured stdout call -----------------------------\n\u5728login_requests\u91cc\u9762\u6253\u5370\u4e86\uff1a{&amp;#x27;username&amp;#x27;: &amp;#x27;byhy&amp;#x27;, &amp;#x27;password&amp;#x27;: &amp;#x27;None&amp;#x27;}\n\u5728cases\u91cc\u9762\uff1ars_code:200,rs_ret:1,rs_msg:\u7528\u6237\u540d\u6216\u8005\u5bc6\u7801\u9519\u8bef\n&#34;}], &#34;case/login_test.py::Test_api0001_0004::test_login_api[byhy-88888888-0-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api0001_0004::test_login_api[byhy-88888888-0-None]&#34;, &#34;duration&#34;: &#34;9 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api0001_0004::test_login_api[byhy-88888888-0-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;9 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;----------------------------- Captured stdout call -----------------------------\n-----\u66ff\u6362\u524d\u7684\u6a21\u7248-------\ndata:\n  password: ${password}\n  username: ${username}\nmethod: post\nurl: http://127.0.0.1/api/mgr/signin\n\n-----\u66ff\u6362\u540e\u7684\u5b9e\u9645\u6570\u636e-------\ndata:\n  password: 88888888\n  username: byhy\nmethod: post\nurl: http://127.0.0.1/api/mgr/signin\n\n\u5728send_api\u91cc\u9762\u6253\u5370\u4e86{&amp;#x27;data&amp;#x27;: {&amp;#x27;password&amp;#x27;: 88888888, &amp;#x27;username&amp;#x27;: &amp;#x27;byhy&amp;#x27;}, &amp;#x27;method&amp;#x27;: &amp;#x27;post&amp;#x27;, &amp;#x27;url&amp;#x27;: &amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;}\n\u5728cases\u91cc\u9762\uff1ars_code:200,rs_ret:0,rs_msg:None\n&#34;}], &#34;case/login_test.py::Test_api0001_0004::test_login_api[byhy-8888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api0001_0004::test_login_api[byhy-8888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;, &#34;duration&#34;: &#34;3 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api0001_0004::test_login_api[byhy-8888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;3 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;----------------------------- Captured stdout call -----------------------------\n-----\u66ff\u6362\u524d\u7684\u6a21\u7248-------\ndata:\n  password: ${password}\n  username: ${username}\nmethod: post\nurl: http://127.0.0.1/api/mgr/signin\n\n-----\u66ff\u6362\u540e\u7684\u5b9e\u9645\u6570\u636e-------\ndata:\n  password: 8888\n  username: byhy\nmethod: post\nurl: http://127.0.0.1/api/mgr/signin\n\n\u5728send_api\u91cc\u9762\u6253\u5370\u4e86{&amp;#x27;data&amp;#x27;: {&amp;#x27;password&amp;#x27;: 8888, &amp;#x27;username&amp;#x27;: &amp;#x27;byhy&amp;#x27;}, &amp;#x27;method&amp;#x27;: &amp;#x27;post&amp;#x27;, &amp;#x27;url&amp;#x27;: &amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;}\n\u5728cases\u91cc\u9762\uff1ars_code:200,rs_ret:1,rs_msg:\u7528\u6237\u540d\u6216\u8005\u5bc6\u7801\u9519\u8bef\n&#34;}], &#34;case/login_test.py::Test_api0001_0004::test_login_api[None-88888888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api0001_0004::test_login_api[None-88888888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;, &#34;duration&#34;: &#34;3 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api0001_0004::test_login_api[None-88888888-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;3 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;----------------------------- Captured stdout call -----------------------------\n-----\u66ff\u6362\u524d\u7684\u6a21\u7248-------\ndata:\n  password: ${password}\n  username: ${username}\nmethod: post\nurl: http://127.0.0.1/api/mgr/signin\n\n-----\u66ff\u6362\u540e\u7684\u5b9e\u9645\u6570\u636e-------\ndata:\n  password: 88888888\n  username: None\nmethod: post\nurl: http://127.0.0.1/api/mgr/signin\n\n\u5728send_api\u91cc\u9762\u6253\u5370\u4e86{&amp;#x27;data&amp;#x27;: {&amp;#x27;password&amp;#x27;: 88888888, &amp;#x27;username&amp;#x27;: &amp;#x27;None&amp;#x27;}, &amp;#x27;method&amp;#x27;: &amp;#x27;post&amp;#x27;, &amp;#x27;url&amp;#x27;: &amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;}\n\u5728cases\u91cc\u9762\uff1ars_code:200,rs_ret:1,rs_msg:\u7528\u6237\u540d\u6216\u8005\u5bc6\u7801\u9519\u8bef\n&#34;}], &#34;case/login_test.py::Test_api0001_0004::test_login_api[byhy-None-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api0001_0004::test_login_api[byhy-None-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&#34;, &#34;duration&#34;: &#34;2 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api0001_0004::test_login_api[byhy-None-1-\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;2 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;----------------------------- Captured stdout call -----------------------------\n-----\u66ff\u6362\u524d\u7684\u6a21\u7248-------\ndata:\n  password: ${password}\n  username: ${username}\nmethod: post\nurl: http://127.0.0.1/api/mgr/signin\n\n-----\u66ff\u6362\u540e\u7684\u5b9e\u9645\u6570\u636e-------\ndata:\n  password: None\n  username: byhy\nmethod: post\nurl: http://127.0.0.1/api/mgr/signin\n\n\u5728send_api\u91cc\u9762\u6253\u5370\u4e86{&amp;#x27;data&amp;#x27;: {&amp;#x27;password&amp;#x27;: &amp;#x27;None&amp;#x27;, &amp;#x27;username&amp;#x27;: &amp;#x27;byhy&amp;#x27;}, &amp;#x27;method&amp;#x27;: &amp;#x27;post&amp;#x27;, &amp;#x27;url&amp;#x27;: &amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;}\n\u5728cases\u91cc\u9762\uff1ars_code:200,rs_ret:1,rs_msg:\u7528\u6237\u540d\u6216\u8005\u5bc6\u7801\u9519\u8bef\n&#34;}], &#34;case/login_test.py::Test_api0001_0004::test_api_yaml&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api0001_0004::test_api_yaml&#34;, &#34;duration&#34;: &#34;2 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api0001_0004::test_api_yaml&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;2 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;----------------------------- Captured stdout call -----------------------------\n\u5728login_requests\u91cc\u9762\u6253\u5370\u4e86\uff1a{&amp;#x27;username&amp;#x27;: &amp;#x27;byhy&amp;#x27;, &amp;#x27;password&amp;#x27;: &amp;#x27;8888888&amp;#x27;}\n&#34;}], &#34;case/login_test.py::Test_api_0005::test_api_0005&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Failed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api_0005::test_api_0005&#34;, &#34;duration&#34;: &#34;1 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Failed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api_0005::test_api_0005&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;1 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;self = &amp;lt;urllib3.connection.HTTPConnection object at 0x104dcd100&amp;gt;\n\n    def _new_conn(self) -&amp;gt; socket.socket:\n        &amp;quot;&amp;quot;&amp;quot;Establish a socket connection and set nodelay settings on it.\n    \n        :return: New socket connection.\n        &amp;quot;&amp;quot;&amp;quot;\n        try:\n&amp;gt;           sock = connection.create_connection(\n                (self._dns_host, self.port),\n                self.timeout,\n                source_address=self.source_address,\n                socket_options=self.socket_options,\n            )\n\n../../../.venv/lib/python3.9/site-packages/urllib3/connection.py:198: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../.venv/lib/python3.9/site-packages/urllib3/util/connection.py:85: in create_connection\n    raise err\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\naddress = (&amp;#x27;127.0.0.1&amp;#x27;, 8888), timeout = None, source_address = None\nsocket_options = []\n\n    def create_connection(\n        address: tuple[str, int],\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        source_address: tuple[str, int] | None = None,\n        socket_options: _TYPE_SOCKET_OPTIONS | None = None,\n    ) -&amp;gt; socket.socket:\n        &amp;quot;&amp;quot;&amp;quot;Connect to *address* and return the socket object.\n    \n        Convenience function.  Connect to *address* (a 2-tuple ``(host,\n        port)``) and return the socket object.  Passing the optional\n        *timeout* parameter will set the timeout on the socket instance\n        before attempting to connect.  If no *timeout* is supplied, the\n        global default timeout setting returned by :func:`socket.getdefaulttimeout`\n        is used.  If *source_address* is set it must be a tuple of (host, port)\n        for the socket to bind as a source address before making the connection.\n        An host of &amp;#x27;&amp;#x27; or port 0 tells the OS to use the default.\n        &amp;quot;&amp;quot;&amp;quot;\n    \n        host, port = address\n        if host.startswith(&amp;quot;[&amp;quot;):\n            host = host.strip(&amp;quot;[]&amp;quot;)\n        err = None\n    \n        # Using the value from allowed_gai_family() in the context of getaddrinfo lets\n        # us select whether to work with IPv4 DNS records, IPv6 records, or both.\n        # The original create_connection function always returns all records.\n        family = allowed_gai_family()\n    \n        try:\n            host.encode(&amp;quot;idna&amp;quot;)\n        except UnicodeError:\n            raise LocationParseError(f&amp;quot;&amp;#x27;{host}&amp;#x27;, label empty or too long&amp;quot;) from None\n    \n        for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):\n            af, socktype, proto, canonname, sa = res\n            sock = None\n            try:\n                sock = socket.socket(af, socktype, proto)\n    \n                # If provided, set socket level options before connecting.\n                _set_socket_options(sock, socket_options)\n    \n                if timeout is not _DEFAULT_TIMEOUT:\n                    sock.settimeout(timeout)\n                if source_address:\n                    sock.bind(source_address)\n&amp;gt;               sock.connect(sa)\nE               ConnectionRefusedError: [Errno 61] Connection refused\n\n../../../.venv/lib/python3.9/site-packages/urllib3/util/connection.py:73: ConnectionRefusedError\n\nThe above exception was the direct cause of the following exception:\n\nself = &amp;lt;urllib3.connectionpool.HTTPConnectionPool object at 0x104d00520&amp;gt;\nmethod = &amp;#x27;POST&amp;#x27;, url = &amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;\nbody = b&amp;#x27;username=byhy&amp;amp;password=88888888&amp;amp;password=88888888&amp;#x27;\nheaders = {&amp;#x27;User-Agent&amp;#x27;: &amp;#x27;python-requests/2.32.3&amp;#x27;, &amp;#x27;Accept-Encoding&amp;#x27;: &amp;#x27;gzip, deflate&amp;#x27;, &amp;#x27;Accept&amp;#x27;: &amp;#x27;*/*&amp;#x27;, &amp;#x27;Connection&amp;#x27;: &amp;#x27;keep-alive&amp;#x27;, &amp;#x27;Content-Length&amp;#x27;: &amp;#x27;49&amp;#x27;}\nretries = Retry(total=0, connect=None, read=False, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=None, read=None, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=&amp;#x27;http&amp;#x27;, auth=None, host=&amp;#x27;127.0.0.1&amp;#x27;, port=None, path=&amp;#x27;/api/mgr/signin&amp;#x27;, query=None, fragment=None)\ndestination_scheme = &amp;#x27;http&amp;#x27;, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -&amp;gt; BaseHTTPResponse:\n        &amp;quot;&amp;quot;&amp;quot;\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you&amp;#x27;ll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it&amp;#x27;s appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response&amp;#x27;s body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            &amp;#x27;content-encoding&amp;#x27; header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you&amp;#x27;re not preloading\n            the response&amp;#x27;s content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won&amp;#x27;t need to be set because urllib3 will\n            auto-populate the value when needed.\n        &amp;quot;&amp;quot;&amp;quot;\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we&amp;#x27;re connecting to is properly encoded\n        if url.startswith(&amp;quot;/&amp;quot;):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] &amp;lt;https://github.com/urllib3/urllib3/issues/651&amp;gt;\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else&amp;#x27;s copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we&amp;#x27;re going to release the connection in ``finally:``, then\n            # the response doesn&amp;#x27;t need to know about the connection. Otherwise\n            # it will also try to release it and we&amp;#x27;ll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n&amp;gt;           response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../../.venv/lib/python3.9/site-packages/urllib3/connectionpool.py:787: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../.venv/lib/python3.9/site-packages/urllib3/connectionpool.py:493: in _make_request\n    conn.request(\n../../../.venv/lib/python3.9/site-packages/urllib3/connection.py:445: in request\n    self.endheaders()\n/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py:1250: in endheaders\n    self._send_output(message_body, encode_chunked=encode_chunked)\n/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py:1010: in _send_output\n    self.send(msg)\n/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py:950: in send\n    self.connect()\n../../../.venv/lib/python3.9/site-packages/urllib3/connection.py:276: in connect\n    self.sock = self._new_conn()\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = &amp;lt;urllib3.connection.HTTPConnection object at 0x104dcd100&amp;gt;\n\n    def _new_conn(self) -&amp;gt; socket.socket:\n        &amp;quot;&amp;quot;&amp;quot;Establish a socket connection and set nodelay settings on it.\n    \n        :return: New socket connection.\n        &amp;quot;&amp;quot;&amp;quot;\n        try:\n            sock = connection.create_connection(\n                (self._dns_host, self.port),\n                self.timeout,\n                source_address=self.source_address,\n                socket_options=self.socket_options,\n            )\n        except socket.gaierror as e:\n            raise NameResolutionError(self.host, self, e) from e\n        except SocketTimeout as e:\n            raise ConnectTimeoutError(\n                self,\n                f&amp;quot;Connection to {self.host} timed out. (connect timeout={self.timeout})&amp;quot;,\n            ) from e\n    \n        except OSError as e:\n&amp;gt;           raise NewConnectionError(\n                self, f&amp;quot;Failed to establish a new connection: {e}&amp;quot;\n            ) from e\nE           urllib3.exceptions.NewConnectionError: &amp;lt;urllib3.connection.HTTPConnection object at 0x104dcd100&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused\n\n../../../.venv/lib/python3.9/site-packages/urllib3/connection.py:213: NewConnectionError\n\nThe above exception was the direct cause of the following exception:\nTraceback (most recent call last):\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connection.py&amp;quot;, line 198, in _new_conn\n    sock = connection.create_connection(\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/util/connection.py&amp;quot;, line 85, in create_connection\n    raise err\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/util/connection.py&amp;quot;, line 73, in create_connection\n    sock.connect(sa)\nConnectionRefusedError: [Errno 61] Connection refused\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connectionpool.py&amp;quot;, line 787, in urlopen\n    response = self._make_request(\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connectionpool.py&amp;quot;, line 493, in _make_request\n    conn.request(\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connection.py&amp;quot;, line 445, in request\n    self.endheaders()\n  File &amp;quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py&amp;quot;, line 1250, in endheaders\n    self._send_output(message_body, encode_chunked=encode_chunked)\n  File &amp;quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py&amp;quot;, line 1010, in _send_output\n    self.send(msg)\n  File &amp;quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py&amp;quot;, line 950, in send\n    self.connect()\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connection.py&amp;quot;, line 276, in connect\n    self.sock = self._new_conn()\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connection.py&amp;quot;, line 213, in _new_conn\n    raise NewConnectionError(\nurllib3.exceptions.NewConnectionError: &amp;lt;urllib3.connection.HTTPConnection object at 0x104dcd100&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused\n\nThe above exception was the direct cause of the following exception:\n\nurllib3.exceptions.ProxyError: (&amp;#x27;Unable to connect to proxy&amp;#x27;, NewConnectionError(&amp;#x27;&amp;lt;urllib3.connection.HTTPConnection object at 0x104dcd100&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused&amp;#x27;))\n\nThe above exception was the direct cause of the following exception:\n\nself = &amp;lt;requests.adapters.HTTPAdapter object at 0x104d00c70&amp;gt;\nrequest = &amp;lt;PreparedRequest [POST]&amp;gt;, stream = False\ntimeout = Timeout(connect=None, read=None, total=None), verify = True\ncert = None, proxies = OrderedDict([(&amp;#x27;http&amp;#x27;, &amp;#x27;http://127.0.0.1:8888&amp;#x27;)])\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        &amp;quot;&amp;quot;&amp;quot;Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest &amp;lt;PreparedRequest&amp;gt;` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) &amp;lt;timeouts&amp;gt;` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server&amp;#x27;s TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        &amp;quot;&amp;quot;&amp;quot;\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or &amp;quot;Content-Length&amp;quot; in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f&amp;quot;Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, &amp;quot;\n                    f&amp;quot;or a single float to set both timeouts to the same value.&amp;quot;\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n&amp;gt;           resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n\n../../../.venv/lib/python3.9/site-packages/requests/adapters.py:667: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../.venv/lib/python3.9/site-packages/urllib3/connectionpool.py:841: in urlopen\n    retries = retries.increment(\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = Retry(total=0, connect=None, read=False, redirect=None, status=None)\nmethod = &amp;#x27;POST&amp;#x27;, url = &amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;, response = None\nerror = ProxyError(&amp;#x27;Unable to connect to proxy&amp;#x27;, NewConnectionError(&amp;#x27;&amp;lt;urllib3.connection.HTTPConnection object at 0x104dcd100&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused&amp;#x27;))\n_pool = &amp;lt;urllib3.connectionpool.HTTPConnectionPool object at 0x104d00520&amp;gt;\n_stacktrace = &amp;lt;traceback object at 0x104de7c80&amp;gt;\n\n    def increment(\n        self,\n        method: str | None = None,\n        url: str | None = None,\n        response: BaseHTTPResponse | None = None,\n        error: Exception | None = None,\n        _pool: ConnectionPool | None = None,\n        _stacktrace: TracebackType | None = None,\n    ) -&amp;gt; Self:\n        &amp;quot;&amp;quot;&amp;quot;Return a new Retry object with incremented retry counters.\n    \n        :param response: A response object, or None, if the server did not\n            return a response.\n        :type response: :class:`~urllib3.response.BaseHTTPResponse`\n        :param Exception error: An error encountered during the request, or\n            None if the response was received successfully.\n    \n        :return: A new ``Retry`` object.\n        &amp;quot;&amp;quot;&amp;quot;\n        if self.total is False and error:\n            # Disabled, indicate to re-raise the error.\n            raise reraise(type(error), error, _stacktrace)\n    \n        total = self.total\n        if total is not None:\n            total -= 1\n    \n        connect = self.connect\n        read = self.read\n        redirect = self.redirect\n        status_count = self.status\n        other = self.other\n        cause = &amp;quot;unknown&amp;quot;\n        status = None\n        redirect_location = None\n    \n        if error and self._is_connection_error(error):\n            # Connect retry?\n            if connect is False:\n                raise reraise(type(error), error, _stacktrace)\n            elif connect is not None:\n                connect -= 1\n    \n        elif error and self._is_read_error(error):\n            # Read retry?\n            if read is False or method is None or not self._is_method_retryable(method):\n                raise reraise(type(error), error, _stacktrace)\n            elif read is not None:\n                read -= 1\n    \n        elif error:\n            # Other retry?\n            if other is not None:\n                other -= 1\n    \n        elif response and response.get_redirect_location():\n            # Redirect retry?\n            if redirect is not None:\n                redirect -= 1\n            cause = &amp;quot;too many redirects&amp;quot;\n            response_redirect_location = response.get_redirect_location()\n            if response_redirect_location:\n                redirect_location = response_redirect_location\n            status = response.status\n    \n        else:\n            # Incrementing because of a server error like a 500 in\n            # status_forcelist and the given method is in the allowed_methods\n            cause = ResponseError.GENERIC_ERROR\n            if response and response.status:\n                if status_count is not None:\n                    status_count -= 1\n                cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)\n                status = response.status\n    \n        history = self.history + (\n            RequestHistory(method, url, error, status, redirect_location),\n        )\n    \n        new_retry = self.new(\n            total=total,\n            connect=connect,\n            read=read,\n            redirect=redirect,\n            status=status_count,\n            other=other,\n            history=history,\n        )\n    \n        if new_retry.is_exhausted():\n            reason = error or ResponseError(cause)\n&amp;gt;           raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]\nE           urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host=&amp;#x27;127.0.0.1&amp;#x27;, port=8888): Max retries exceeded with url: http://127.0.0.1/api/mgr/signin (Caused by ProxyError(&amp;#x27;Unable to connect to proxy&amp;#x27;, NewConnectionError(&amp;#x27;&amp;lt;urllib3.connection.HTTPConnection object at 0x104dcd100&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused&amp;#x27;)))\n\n../../../.venv/lib/python3.9/site-packages/urllib3/util/retry.py:519: MaxRetryError\n\nDuring handling of the above exception, another exception occurred:\n\nself = &amp;lt;login_test.Test_api_0005 object at 0x104d14610&amp;gt;\n\n    def test_api_0005(self):\n        data = &amp;#x27;username=byhy&amp;amp;password=88888888&amp;amp;password=88888888&amp;#x27;\n    \n&amp;gt;       response = requests.post(&amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;,data=data.encode(&amp;#x27;utf8&amp;#x27;),proxies={&amp;#x27;http&amp;#x27;:&amp;#x27;http://127.0.0.1:8888&amp;#x27;})\n\ncase/login_test.py:99: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../.venv/lib/python3.9/site-packages/requests/api.py:115: in post\n    return request(&amp;quot;post&amp;quot;, url, data=data, json=json, **kwargs)\n../../../.venv/lib/python3.9/site-packages/requests/api.py:59: in request\n    return session.request(method=method, url=url, **kwargs)\n../../../.venv/lib/python3.9/site-packages/requests/sessions.py:589: in request\n    resp = self.send(prep, **send_kwargs)\n../../../.venv/lib/python3.9/site-packages/requests/sessions.py:703: in send\n    r = adapter.send(request, **kwargs)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = &amp;lt;requests.adapters.HTTPAdapter object at 0x104d00c70&amp;gt;\nrequest = &amp;lt;PreparedRequest [POST]&amp;gt;, stream = False\ntimeout = Timeout(connect=None, read=None, total=None), verify = True\ncert = None, proxies = OrderedDict([(&amp;#x27;http&amp;#x27;, &amp;#x27;http://127.0.0.1:8888&amp;#x27;)])\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        &amp;quot;&amp;quot;&amp;quot;Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest &amp;lt;PreparedRequest&amp;gt;` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) &amp;lt;timeouts&amp;gt;` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server&amp;#x27;s TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        &amp;quot;&amp;quot;&amp;quot;\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or &amp;quot;Content-Length&amp;quot; in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f&amp;quot;Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, &amp;quot;\n                    f&amp;quot;or a single float to set both timeouts to the same value.&amp;quot;\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n            resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n    \n        except (ProtocolError, OSError) as err:\n            raise ConnectionError(err, request=request)\n    \n        except MaxRetryError as e:\n            if isinstance(e.reason, ConnectTimeoutError):\n                # TODO: Remove this in 3.0.0: see #2811\n                if not isinstance(e.reason, NewConnectionError):\n                    raise ConnectTimeout(e, request=request)\n    \n            if isinstance(e.reason, ResponseError):\n                raise RetryError(e, request=request)\n    \n            if isinstance(e.reason, _ProxyError):\n&amp;gt;               raise ProxyError(e, request=request)\nE               requests.exceptions.ProxyError: HTTPConnectionPool(host=&amp;#x27;127.0.0.1&amp;#x27;, port=8888): Max retries exceeded with url: http://127.0.0.1/api/mgr/signin (Caused by ProxyError(&amp;#x27;Unable to connect to proxy&amp;#x27;, NewConnectionError(&amp;#x27;&amp;lt;urllib3.connection.HTTPConnection object at 0x104dcd100&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused&amp;#x27;)))\n\n../../../.venv/lib/python3.9/site-packages/requests/adapters.py:694: ProxyError\n&#34;}], &#34;case/login_test.py::Test_api_0006::test_api_0006&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Failed&#34;, &#34;testId&#34;: &#34;case/login_test.py::Test_api_0006::test_api_0006&#34;, &#34;duration&#34;: &#34;1 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Failed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;case/login_test.py::Test_api_0006::test_api_0006&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;1 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;self = &amp;lt;urllib3.connection.HTTPConnection object at 0x105a09df0&amp;gt;\n\n    def _new_conn(self) -&amp;gt; socket.socket:\n        &amp;quot;&amp;quot;&amp;quot;Establish a socket connection and set nodelay settings on it.\n    \n        :return: New socket connection.\n        &amp;quot;&amp;quot;&amp;quot;\n        try:\n&amp;gt;           sock = connection.create_connection(\n                (self._dns_host, self.port),\n                self.timeout,\n                source_address=self.source_address,\n                socket_options=self.socket_options,\n            )\n\n../../../.venv/lib/python3.9/site-packages/urllib3/connection.py:198: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../.venv/lib/python3.9/site-packages/urllib3/util/connection.py:85: in create_connection\n    raise err\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\naddress = (&amp;#x27;127.0.0.1&amp;#x27;, 8888), timeout = None, source_address = None\nsocket_options = []\n\n    def create_connection(\n        address: tuple[str, int],\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        source_address: tuple[str, int] | None = None,\n        socket_options: _TYPE_SOCKET_OPTIONS | None = None,\n    ) -&amp;gt; socket.socket:\n        &amp;quot;&amp;quot;&amp;quot;Connect to *address* and return the socket object.\n    \n        Convenience function.  Connect to *address* (a 2-tuple ``(host,\n        port)``) and return the socket object.  Passing the optional\n        *timeout* parameter will set the timeout on the socket instance\n        before attempting to connect.  If no *timeout* is supplied, the\n        global default timeout setting returned by :func:`socket.getdefaulttimeout`\n        is used.  If *source_address* is set it must be a tuple of (host, port)\n        for the socket to bind as a source address before making the connection.\n        An host of &amp;#x27;&amp;#x27; or port 0 tells the OS to use the default.\n        &amp;quot;&amp;quot;&amp;quot;\n    \n        host, port = address\n        if host.startswith(&amp;quot;[&amp;quot;):\n            host = host.strip(&amp;quot;[]&amp;quot;)\n        err = None\n    \n        # Using the value from allowed_gai_family() in the context of getaddrinfo lets\n        # us select whether to work with IPv4 DNS records, IPv6 records, or both.\n        # The original create_connection function always returns all records.\n        family = allowed_gai_family()\n    \n        try:\n            host.encode(&amp;quot;idna&amp;quot;)\n        except UnicodeError:\n            raise LocationParseError(f&amp;quot;&amp;#x27;{host}&amp;#x27;, label empty or too long&amp;quot;) from None\n    \n        for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):\n            af, socktype, proto, canonname, sa = res\n            sock = None\n            try:\n                sock = socket.socket(af, socktype, proto)\n    \n                # If provided, set socket level options before connecting.\n                _set_socket_options(sock, socket_options)\n    \n                if timeout is not _DEFAULT_TIMEOUT:\n                    sock.settimeout(timeout)\n                if source_address:\n                    sock.bind(source_address)\n&amp;gt;               sock.connect(sa)\nE               ConnectionRefusedError: [Errno 61] Connection refused\n\n../../../.venv/lib/python3.9/site-packages/urllib3/util/connection.py:73: ConnectionRefusedError\n\nThe above exception was the direct cause of the following exception:\n\nself = &amp;lt;urllib3.connectionpool.HTTPConnectionPool object at 0x1058ee0a0&amp;gt;\nmethod = &amp;#x27;POST&amp;#x27;, url = &amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;\nbody = b&amp;#x27;username=byhy&amp;amp;username=byhy&amp;amp;password=88888888&amp;#x27;\nheaders = {&amp;#x27;User-Agent&amp;#x27;: &amp;#x27;python-requests/2.32.3&amp;#x27;, &amp;#x27;Accept-Encoding&amp;#x27;: &amp;#x27;gzip, deflate&amp;#x27;, &amp;#x27;Accept&amp;#x27;: &amp;#x27;*/*&amp;#x27;, &amp;#x27;Connection&amp;#x27;: &amp;#x27;keep-alive&amp;#x27;, &amp;#x27;Content-Length&amp;#x27;: &amp;#x27;45&amp;#x27;}\nretries = Retry(total=0, connect=None, read=False, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=None, read=None, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=&amp;#x27;http&amp;#x27;, auth=None, host=&amp;#x27;127.0.0.1&amp;#x27;, port=None, path=&amp;#x27;/api/mgr/signin&amp;#x27;, query=None, fragment=None)\ndestination_scheme = &amp;#x27;http&amp;#x27;, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -&amp;gt; BaseHTTPResponse:\n        &amp;quot;&amp;quot;&amp;quot;\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you&amp;#x27;ll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it&amp;#x27;s appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response&amp;#x27;s body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            &amp;#x27;content-encoding&amp;#x27; header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you&amp;#x27;re not preloading\n            the response&amp;#x27;s content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won&amp;#x27;t need to be set because urllib3 will\n            auto-populate the value when needed.\n        &amp;quot;&amp;quot;&amp;quot;\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we&amp;#x27;re connecting to is properly encoded\n        if url.startswith(&amp;quot;/&amp;quot;):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] &amp;lt;https://github.com/urllib3/urllib3/issues/651&amp;gt;\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else&amp;#x27;s copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we&amp;#x27;re going to release the connection in ``finally:``, then\n            # the response doesn&amp;#x27;t need to know about the connection. Otherwise\n            # it will also try to release it and we&amp;#x27;ll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n&amp;gt;           response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../../.venv/lib/python3.9/site-packages/urllib3/connectionpool.py:787: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../.venv/lib/python3.9/site-packages/urllib3/connectionpool.py:493: in _make_request\n    conn.request(\n../../../.venv/lib/python3.9/site-packages/urllib3/connection.py:445: in request\n    self.endheaders()\n/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py:1250: in endheaders\n    self._send_output(message_body, encode_chunked=encode_chunked)\n/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py:1010: in _send_output\n    self.send(msg)\n/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py:950: in send\n    self.connect()\n../../../.venv/lib/python3.9/site-packages/urllib3/connection.py:276: in connect\n    self.sock = self._new_conn()\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = &amp;lt;urllib3.connection.HTTPConnection object at 0x105a09df0&amp;gt;\n\n    def _new_conn(self) -&amp;gt; socket.socket:\n        &amp;quot;&amp;quot;&amp;quot;Establish a socket connection and set nodelay settings on it.\n    \n        :return: New socket connection.\n        &amp;quot;&amp;quot;&amp;quot;\n        try:\n            sock = connection.create_connection(\n                (self._dns_host, self.port),\n                self.timeout,\n                source_address=self.source_address,\n                socket_options=self.socket_options,\n            )\n        except socket.gaierror as e:\n            raise NameResolutionError(self.host, self, e) from e\n        except SocketTimeout as e:\n            raise ConnectTimeoutError(\n                self,\n                f&amp;quot;Connection to {self.host} timed out. (connect timeout={self.timeout})&amp;quot;,\n            ) from e\n    \n        except OSError as e:\n&amp;gt;           raise NewConnectionError(\n                self, f&amp;quot;Failed to establish a new connection: {e}&amp;quot;\n            ) from e\nE           urllib3.exceptions.NewConnectionError: &amp;lt;urllib3.connection.HTTPConnection object at 0x105a09df0&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused\n\n../../../.venv/lib/python3.9/site-packages/urllib3/connection.py:213: NewConnectionError\n\nThe above exception was the direct cause of the following exception:\nTraceback (most recent call last):\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connection.py&amp;quot;, line 198, in _new_conn\n    sock = connection.create_connection(\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/util/connection.py&amp;quot;, line 85, in create_connection\n    raise err\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/util/connection.py&amp;quot;, line 73, in create_connection\n    sock.connect(sa)\nConnectionRefusedError: [Errno 61] Connection refused\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connectionpool.py&amp;quot;, line 787, in urlopen\n    response = self._make_request(\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connectionpool.py&amp;quot;, line 493, in _make_request\n    conn.request(\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connection.py&amp;quot;, line 445, in request\n    self.endheaders()\n  File &amp;quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py&amp;quot;, line 1250, in endheaders\n    self._send_output(message_body, encode_chunked=encode_chunked)\n  File &amp;quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py&amp;quot;, line 1010, in _send_output\n    self.send(msg)\n  File &amp;quot;/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/http/client.py&amp;quot;, line 950, in send\n    self.connect()\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connection.py&amp;quot;, line 276, in connect\n    self.sock = self._new_conn()\n  File &amp;quot;/Users/show/PythonAndQA(code)/python-study2025/.venv/lib/python3.9/site-packages/urllib3/connection.py&amp;quot;, line 213, in _new_conn\n    raise NewConnectionError(\nurllib3.exceptions.NewConnectionError: &amp;lt;urllib3.connection.HTTPConnection object at 0x105a09df0&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused\n\nThe above exception was the direct cause of the following exception:\n\nurllib3.exceptions.ProxyError: (&amp;#x27;Unable to connect to proxy&amp;#x27;, NewConnectionError(&amp;#x27;&amp;lt;urllib3.connection.HTTPConnection object at 0x105a09df0&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused&amp;#x27;))\n\nThe above exception was the direct cause of the following exception:\n\nself = &amp;lt;requests.adapters.HTTPAdapter object at 0x1058ee370&amp;gt;\nrequest = &amp;lt;PreparedRequest [POST]&amp;gt;, stream = False\ntimeout = Timeout(connect=None, read=None, total=None), verify = True\ncert = None, proxies = OrderedDict([(&amp;#x27;http&amp;#x27;, &amp;#x27;http://127.0.0.1:8888&amp;#x27;)])\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        &amp;quot;&amp;quot;&amp;quot;Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest &amp;lt;PreparedRequest&amp;gt;` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) &amp;lt;timeouts&amp;gt;` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server&amp;#x27;s TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        &amp;quot;&amp;quot;&amp;quot;\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or &amp;quot;Content-Length&amp;quot; in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f&amp;quot;Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, &amp;quot;\n                    f&amp;quot;or a single float to set both timeouts to the same value.&amp;quot;\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n&amp;gt;           resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n\n../../../.venv/lib/python3.9/site-packages/requests/adapters.py:667: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../.venv/lib/python3.9/site-packages/urllib3/connectionpool.py:841: in urlopen\n    retries = retries.increment(\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = Retry(total=0, connect=None, read=False, redirect=None, status=None)\nmethod = &amp;#x27;POST&amp;#x27;, url = &amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;, response = None\nerror = ProxyError(&amp;#x27;Unable to connect to proxy&amp;#x27;, NewConnectionError(&amp;#x27;&amp;lt;urllib3.connection.HTTPConnection object at 0x105a09df0&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused&amp;#x27;))\n_pool = &amp;lt;urllib3.connectionpool.HTTPConnectionPool object at 0x1058ee0a0&amp;gt;\n_stacktrace = &amp;lt;traceback object at 0x1059ded00&amp;gt;\n\n    def increment(\n        self,\n        method: str | None = None,\n        url: str | None = None,\n        response: BaseHTTPResponse | None = None,\n        error: Exception | None = None,\n        _pool: ConnectionPool | None = None,\n        _stacktrace: TracebackType | None = None,\n    ) -&amp;gt; Self:\n        &amp;quot;&amp;quot;&amp;quot;Return a new Retry object with incremented retry counters.\n    \n        :param response: A response object, or None, if the server did not\n            return a response.\n        :type response: :class:`~urllib3.response.BaseHTTPResponse`\n        :param Exception error: An error encountered during the request, or\n            None if the response was received successfully.\n    \n        :return: A new ``Retry`` object.\n        &amp;quot;&amp;quot;&amp;quot;\n        if self.total is False and error:\n            # Disabled, indicate to re-raise the error.\n            raise reraise(type(error), error, _stacktrace)\n    \n        total = self.total\n        if total is not None:\n            total -= 1\n    \n        connect = self.connect\n        read = self.read\n        redirect = self.redirect\n        status_count = self.status\n        other = self.other\n        cause = &amp;quot;unknown&amp;quot;\n        status = None\n        redirect_location = None\n    \n        if error and self._is_connection_error(error):\n            # Connect retry?\n            if connect is False:\n                raise reraise(type(error), error, _stacktrace)\n            elif connect is not None:\n                connect -= 1\n    \n        elif error and self._is_read_error(error):\n            # Read retry?\n            if read is False or method is None or not self._is_method_retryable(method):\n                raise reraise(type(error), error, _stacktrace)\n            elif read is not None:\n                read -= 1\n    \n        elif error:\n            # Other retry?\n            if other is not None:\n                other -= 1\n    \n        elif response and response.get_redirect_location():\n            # Redirect retry?\n            if redirect is not None:\n                redirect -= 1\n            cause = &amp;quot;too many redirects&amp;quot;\n            response_redirect_location = response.get_redirect_location()\n            if response_redirect_location:\n                redirect_location = response_redirect_location\n            status = response.status\n    \n        else:\n            # Incrementing because of a server error like a 500 in\n            # status_forcelist and the given method is in the allowed_methods\n            cause = ResponseError.GENERIC_ERROR\n            if response and response.status:\n                if status_count is not None:\n                    status_count -= 1\n                cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)\n                status = response.status\n    \n        history = self.history + (\n            RequestHistory(method, url, error, status, redirect_location),\n        )\n    \n        new_retry = self.new(\n            total=total,\n            connect=connect,\n            read=read,\n            redirect=redirect,\n            status=status_count,\n            other=other,\n            history=history,\n        )\n    \n        if new_retry.is_exhausted():\n            reason = error or ResponseError(cause)\n&amp;gt;           raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]\nE           urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host=&amp;#x27;127.0.0.1&amp;#x27;, port=8888): Max retries exceeded with url: http://127.0.0.1/api/mgr/signin (Caused by ProxyError(&amp;#x27;Unable to connect to proxy&amp;#x27;, NewConnectionError(&amp;#x27;&amp;lt;urllib3.connection.HTTPConnection object at 0x105a09df0&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused&amp;#x27;)))\n\n../../../.venv/lib/python3.9/site-packages/urllib3/util/retry.py:519: MaxRetryError\n\nDuring handling of the above exception, another exception occurred:\n\nself = &amp;lt;login_test.Test_api_0006 object at 0x104d14460&amp;gt;\n\n    def test_api_0006(self):\n        data = &amp;#x27;username=byhy&amp;amp;username=byhy&amp;amp;password=88888888&amp;#x27;\n    \n&amp;gt;       response = requests.post(&amp;#x27;http://127.0.0.1/api/mgr/signin&amp;#x27;,data=data.encode(&amp;#x27;utf8&amp;#x27;),proxies={&amp;#x27;http&amp;#x27;:&amp;#x27;http://127.0.0.1:8888&amp;#x27;})\n\ncase/login_test.py:119: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../.venv/lib/python3.9/site-packages/requests/api.py:115: in post\n    return request(&amp;quot;post&amp;quot;, url, data=data, json=json, **kwargs)\n../../../.venv/lib/python3.9/site-packages/requests/api.py:59: in request\n    return session.request(method=method, url=url, **kwargs)\n../../../.venv/lib/python3.9/site-packages/requests/sessions.py:589: in request\n    resp = self.send(prep, **send_kwargs)\n../../../.venv/lib/python3.9/site-packages/requests/sessions.py:703: in send\n    r = adapter.send(request, **kwargs)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = &amp;lt;requests.adapters.HTTPAdapter object at 0x1058ee370&amp;gt;\nrequest = &amp;lt;PreparedRequest [POST]&amp;gt;, stream = False\ntimeout = Timeout(connect=None, read=None, total=None), verify = True\ncert = None, proxies = OrderedDict([(&amp;#x27;http&amp;#x27;, &amp;#x27;http://127.0.0.1:8888&amp;#x27;)])\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        &amp;quot;&amp;quot;&amp;quot;Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest &amp;lt;PreparedRequest&amp;gt;` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) &amp;lt;timeouts&amp;gt;` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server&amp;#x27;s TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        &amp;quot;&amp;quot;&amp;quot;\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or &amp;quot;Content-Length&amp;quot; in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f&amp;quot;Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, &amp;quot;\n                    f&amp;quot;or a single float to set both timeouts to the same value.&amp;quot;\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n            resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n    \n        except (ProtocolError, OSError) as err:\n            raise ConnectionError(err, request=request)\n    \n        except MaxRetryError as e:\n            if isinstance(e.reason, ConnectTimeoutError):\n                # TODO: Remove this in 3.0.0: see #2811\n                if not isinstance(e.reason, NewConnectionError):\n                    raise ConnectTimeout(e, request=request)\n    \n            if isinstance(e.reason, ResponseError):\n                raise RetryError(e, request=request)\n    \n            if isinstance(e.reason, _ProxyError):\n&amp;gt;               raise ProxyError(e, request=request)\nE               requests.exceptions.ProxyError: HTTPConnectionPool(host=&amp;#x27;127.0.0.1&amp;#x27;, port=8888): Max retries exceeded with url: http://127.0.0.1/api/mgr/signin (Caused by ProxyError(&amp;#x27;Unable to connect to proxy&amp;#x27;, NewConnectionError(&amp;#x27;&amp;lt;urllib3.connection.HTTPConnection object at 0x105a09df0&amp;gt;: Failed to establish a new connection: [Errno 61] Connection refused&amp;#x27;)))\n\n../../../.venv/lib/python3.9/site-packages/requests/adapters.py:694: ProxyError\n&#34;}]}, &#34;renderCollapsed&#34;: [&#34;passed&#34;], &#34;initialSort&#34;: &#34;result&#34;, &#34;title&#34;: &#34;report.html&#34;}"></div>
    <script>
      (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
const { getCollapsedCategory, setCollapsedIds } = require('./storage.js')

class DataManager {
    setManager(data) {
        const collapsedCategories = [...getCollapsedCategory(data.renderCollapsed)]
        const collapsedIds = []
        const tests = Object.values(data.tests).flat().map((test, index) => {
            const collapsed = collapsedCategories.includes(test.result.toLowerCase())
            const id = `test_${index}`
            if (collapsed) {
                collapsedIds.push(id)
            }
            return {
                ...test,
                id,
                collapsed,
            }
        })
        const dataBlob = { ...data, tests }
        this.data = { ...dataBlob }
        this.renderData = { ...dataBlob }
        setCollapsedIds(collapsedIds)
    }

    get allData() {
        return { ...this.data }
    }

    resetRender() {
        this.renderData = { ...this.data }
    }

    setRender(data) {
        this.renderData.tests = [...data]
    }

    toggleCollapsedItem(id) {
        this.renderData.tests = this.renderData.tests.map((test) =>
            test.id === id ? { ...test, collapsed: !test.collapsed } : test,
        )
    }

    set allCollapsed(collapsed) {
        this.renderData = { ...this.renderData, tests: [...this.renderData.tests.map((test) => (
            { ...test, collapsed }
        ))] }
    }

    get testSubset() {
        return [...this.renderData.tests]
    }

    get environment() {
        return this.renderData.environment
    }

    get initialSort() {
        return this.data.initialSort
    }
}

module.exports = {
    manager: new DataManager(),
}

},{"./storage.js":8}],2:[function(require,module,exports){
const mediaViewer = require('./mediaviewer.js')
const templateEnvRow = document.getElementById('template_environment_row')
const templateResult = document.getElementById('template_results-table__tbody')

function htmlToElements(html) {
    const temp = document.createElement('template')
    temp.innerHTML = html
    return temp.content.childNodes
}

const find = (selector, elem) => {
    if (!elem) {
        elem = document
    }
    return elem.querySelector(selector)
}

const findAll = (selector, elem) => {
    if (!elem) {
        elem = document
    }
    return [...elem.querySelectorAll(selector)]
}

const dom = {
    getStaticRow: (key, value) => {
        const envRow = templateEnvRow.content.cloneNode(true)
        const isObj = typeof value === 'object' && value !== null
        const values = isObj ? Object.keys(value).map((k) => `${k}: ${value[k]}`) : null

        const valuesElement = htmlToElements(
            values ? `<ul>${values.map((val) => `<li>${val}</li>`).join('')}<ul>` : `<div>${value}</div>`)[0]
        const td = findAll('td', envRow)
        td[0].textContent = key
        td[1].appendChild(valuesElement)

        return envRow
    },
    getResultTBody: ({ testId, id, log, extras, resultsTableRow, tableHtml, result, collapsed }) => {
        const resultBody = templateResult.content.cloneNode(true)
        resultBody.querySelector('tbody').classList.add(result.toLowerCase())
        resultBody.querySelector('tbody').id = testId
        resultBody.querySelector('.collapsible').dataset.id = id

        resultsTableRow.forEach((html) => {
            const t = document.createElement('template')
            t.innerHTML = html
            resultBody.querySelector('.collapsible').appendChild(t.content)
        })

        if (log) {
            // Wrap lines starting with "E" with span.error to color those lines red
            const wrappedLog = log.replace(/^E.*$/gm, (match) => `<span class="error">${match}</span>`)
            resultBody.querySelector('.log').innerHTML = wrappedLog
        } else {
            resultBody.querySelector('.log').remove()
        }

        if (collapsed) {
            resultBody.querySelector('.collapsible > td')?.classList.add('collapsed')
            resultBody.querySelector('.extras-row').classList.add('hidden')
        } else {
            resultBody.querySelector('.collapsible > td')?.classList.remove('collapsed')
        }

        const media = []
        extras?.forEach(({ name, format_type, content }) => {
            if (['image', 'video'].includes(format_type)) {
                media.push({ path: content, name, format_type })
            }

            if (format_type === 'html') {
                resultBody.querySelector('.extraHTML').insertAdjacentHTML('beforeend', `<div>${content}</div>`)
            }
        })
        mediaViewer.setup(resultBody, media)

        // Add custom html from the pytest_html_results_table_html hook
        tableHtml?.forEach((item) => {
            resultBody.querySelector('td[class="extra"]').insertAdjacentHTML('beforeend', item)
        })

        return resultBody
    },
}

module.exports = {
    dom,
    htmlToElements,
    find,
    findAll,
}

},{"./mediaviewer.js":6}],3:[function(require,module,exports){
const { manager } = require('./datamanager.js')
const { doSort } = require('./sort.js')
const storageModule = require('./storage.js')

const getFilteredSubSet = (filter) =>
    manager.allData.tests.filter(({ result }) => filter.includes(result.toLowerCase()))

const doInitFilter = () => {
    const currentFilter = storageModule.getVisible()
    const filteredSubset = getFilteredSubSet(currentFilter)
    manager.setRender(filteredSubset)
}

const doFilter = (type, show) => {
    if (show) {
        storageModule.showCategory(type)
    } else {
        storageModule.hideCategory(type)
    }

    const currentFilter = storageModule.getVisible()
    const filteredSubset = getFilteredSubSet(currentFilter)
    manager.setRender(filteredSubset)

    const sortColumn = storageModule.getSort()
    doSort(sortColumn, true)
}

module.exports = {
    doFilter,
    doInitFilter,
}

},{"./datamanager.js":1,"./sort.js":7,"./storage.js":8}],4:[function(require,module,exports){
const { redraw, bindEvents, renderStatic } = require('./main.js')
const { doInitFilter } = require('./filter.js')
const { doInitSort } = require('./sort.js')
const { manager } = require('./datamanager.js')
const data = JSON.parse(document.getElementById('data-container').dataset.jsonblob)

function init() {
    manager.setManager(data)
    doInitFilter()
    doInitSort()
    renderStatic()
    redraw()
    bindEvents()
}

init()

},{"./datamanager.js":1,"./filter.js":3,"./main.js":5,"./sort.js":7}],5:[function(require,module,exports){
const { dom, find, findAll } = require('./dom.js')
const { manager } = require('./datamanager.js')
const { doSort } = require('./sort.js')
const { doFilter } = require('./filter.js')
const {
    getVisible,
    getCollapsedIds,
    setCollapsedIds,
    getSort,
    getSortDirection,
    possibleFilters,
} = require('./storage.js')

const removeChildren = (node) => {
    while (node.firstChild) {
        node.removeChild(node.firstChild)
    }
}

const renderStatic = () => {
    const renderEnvironmentTable = () => {
        const environment = manager.environment
        const rows = Object.keys(environment).map((key) => dom.getStaticRow(key, environment[key]))
        const table = document.getElementById('environment')
        removeChildren(table)
        rows.forEach((row) => table.appendChild(row))
    }
    renderEnvironmentTable()
}

const addItemToggleListener = (elem) => {
    elem.addEventListener('click', ({ target }) => {
        const id = target.parentElement.dataset.id
        manager.toggleCollapsedItem(id)

        const collapsedIds = getCollapsedIds()
        if (collapsedIds.includes(id)) {
            const updated = collapsedIds.filter((item) => item !== id)
            setCollapsedIds(updated)
        } else {
            collapsedIds.push(id)
            setCollapsedIds(collapsedIds)
        }
        redraw()
    })
}

const renderContent = (tests) => {
    const sortAttr = getSort(manager.initialSort)
    const sortAsc = JSON.parse(getSortDirection())
    const rows = tests.map(dom.getResultTBody)
    const table = document.getElementById('results-table')
    const tableHeader = document.getElementById('results-table-head')

    const newTable = document.createElement('table')
    newTable.id = 'results-table'

    // remove all sorting classes and set the relevant
    findAll('.sortable', tableHeader).forEach((elem) => elem.classList.remove('asc', 'desc'))
    tableHeader.querySelector(`.sortable[data-column-type="${sortAttr}"]`)?.classList.add(sortAsc ? 'desc' : 'asc')
    newTable.appendChild(tableHeader)

    if (!rows.length) {
        const emptyTable = document.getElementById('template_results-table__body--empty').content.cloneNode(true)
        newTable.appendChild(emptyTable)
    } else {
        rows.forEach((row) => {
            if (!!row) {
                findAll('.collapsible td:not(.col-links', row).forEach(addItemToggleListener)
                find('.logexpander', row).addEventListener('click',
                    (evt) => evt.target.parentNode.classList.toggle('expanded'),
                )
                newTable.appendChild(row)
            }
        })
    }

    table.replaceWith(newTable)
}

const renderDerived = () => {
    const currentFilter = getVisible()
    possibleFilters.forEach((result) => {
        const input = document.querySelector(`input[data-test-result="${result}"]`)
        input.checked = currentFilter.includes(result)
    })
}

const bindEvents = () => {
    const filterColumn = (evt) => {
        const { target: element } = evt
        const { testResult } = element.dataset

        doFilter(testResult, element.checked)
        const collapsedIds = getCollapsedIds()
        const updated = manager.renderData.tests.map((test) => {
            return {
                ...test,
                collapsed: collapsedIds.includes(test.id),
            }
        })
        manager.setRender(updated)
        redraw()
    }

    const header = document.getElementById('environment-header')
    header.addEventListener('click', () => {
        const table = document.getElementById('environment')
        table.classList.toggle('hidden')
        header.classList.toggle('collapsed')
    })

    findAll('input[name="filter_checkbox"]').forEach((elem) => {
        elem.addEventListener('click', filterColumn)
    })

    findAll('.sortable').forEach((elem) => {
        elem.addEventListener('click', (evt) => {
            const { target: element } = evt
            const { columnType } = element.dataset
            doSort(columnType)
            redraw()
        })
    })

    document.getElementById('show_all_details').addEventListener('click', () => {
        manager.allCollapsed = false
        setCollapsedIds([])
        redraw()
    })
    document.getElementById('hide_all_details').addEventListener('click', () => {
        manager.allCollapsed = true
        const allIds = manager.renderData.tests.map((test) => test.id)
        setCollapsedIds(allIds)
        redraw()
    })
}

const redraw = () => {
    const { testSubset } = manager

    renderContent(testSubset)
    renderDerived()
}

module.exports = {
    redraw,
    bindEvents,
    renderStatic,
}

},{"./datamanager.js":1,"./dom.js":2,"./filter.js":3,"./sort.js":7,"./storage.js":8}],6:[function(require,module,exports){
class MediaViewer {
    constructor(assets) {
        this.assets = assets
        this.index = 0
    }

    nextActive() {
        this.index = this.index === this.assets.length - 1 ? 0 : this.index + 1
        return [this.activeFile, this.index]
    }

    prevActive() {
        this.index = this.index === 0 ? this.assets.length - 1 : this.index -1
        return [this.activeFile, this.index]
    }

    get currentIndex() {
        return this.index
    }

    get activeFile() {
        return this.assets[this.index]
    }
}


const setup = (resultBody, assets) => {
    if (!assets.length) {
        resultBody.querySelector('.media').classList.add('hidden')
        return
    }

    const mediaViewer = new MediaViewer(assets)
    const container = resultBody.querySelector('.media-container')
    const leftArrow = resultBody.querySelector('.media-container__nav--left')
    const rightArrow = resultBody.querySelector('.media-container__nav--right')
    const mediaName = resultBody.querySelector('.media__name')
    const counter = resultBody.querySelector('.media__counter')
    const imageEl = resultBody.querySelector('img')
    const sourceEl = resultBody.querySelector('source')
    const videoEl = resultBody.querySelector('video')

    const setImg = (media, index) => {
        if (media?.format_type === 'image') {
            imageEl.src = media.path

            imageEl.classList.remove('hidden')
            videoEl.classList.add('hidden')
        } else if (media?.format_type === 'video') {
            sourceEl.src = media.path

            videoEl.classList.remove('hidden')
            imageEl.classList.add('hidden')
        }

        mediaName.innerText = media?.name
        counter.innerText = `${index + 1} / ${assets.length}`
    }
    setImg(mediaViewer.activeFile, mediaViewer.currentIndex)

    const moveLeft = () => {
        const [media, index] = mediaViewer.prevActive()
        setImg(media, index)
    }
    const doRight = () => {
        const [media, index] = mediaViewer.nextActive()
        setImg(media, index)
    }
    const openImg = () => {
        window.open(mediaViewer.activeFile.path, '_blank')
    }
    if (assets.length === 1) {
        container.classList.add('media-container--fullscreen')
    } else {
        leftArrow.addEventListener('click', moveLeft)
        rightArrow.addEventListener('click', doRight)
    }
    imageEl.addEventListener('click', openImg)
}

module.exports = {
    setup,
}

},{}],7:[function(require,module,exports){
const { manager } = require('./datamanager.js')
const storageModule = require('./storage.js')

const genericSort = (list, key, ascending, customOrder) => {
    let sorted
    if (customOrder) {
        sorted = list.sort((a, b) => {
            const aValue = a.result.toLowerCase()
            const bValue = b.result.toLowerCase()

            const aIndex = customOrder.findIndex((item) => item.toLowerCase() === aValue)
            const bIndex = customOrder.findIndex((item) => item.toLowerCase() === bValue)

            // Compare the indices to determine the sort order
            return aIndex - bIndex
        })
    } else {
        sorted = list.sort((a, b) => a[key] === b[key] ? 0 : a[key] > b[key] ? 1 : -1)
    }

    if (ascending) {
        sorted.reverse()
    }
    return sorted
}

const durationSort = (list, ascending) => {
    const parseDuration = (duration) => {
        if (duration.includes(':')) {
            // If it's in the format "HH:mm:ss"
            const [hours, minutes, seconds] = duration.split(':').map(Number)
            return (hours * 3600 + minutes * 60 + seconds) * 1000
        } else {
            // If it's in the format "nnn ms"
            return parseInt(duration)
        }
    }
    const sorted = list.sort((a, b) => parseDuration(a['duration']) - parseDuration(b['duration']))
    if (ascending) {
        sorted.reverse()
    }
    return sorted
}

const doInitSort = () => {
    const type = storageModule.getSort(manager.initialSort)
    const ascending = storageModule.getSortDirection()
    const list = manager.testSubset
    const initialOrder = ['Error', 'Failed', 'Rerun', 'XFailed', 'XPassed', 'Skipped', 'Passed']

    storageModule.setSort(type)
    storageModule.setSortDirection(ascending)

    if (type?.toLowerCase() === 'original') {
        manager.setRender(list)
    } else {
        let sortedList
        switch (type) {
        case 'duration':
            sortedList = durationSort(list, ascending)
            break
        case 'result':
            sortedList = genericSort(list, type, ascending, initialOrder)
            break
        default:
            sortedList = genericSort(list, type, ascending)
            break
        }
        manager.setRender(sortedList)
    }
}

const doSort = (type, skipDirection) => {
    const newSortType = storageModule.getSort(manager.initialSort) !== type
    const currentAsc = storageModule.getSortDirection()
    let ascending
    if (skipDirection) {
        ascending = currentAsc
    } else {
        ascending = newSortType ? false : !currentAsc
    }
    storageModule.setSort(type)
    storageModule.setSortDirection(ascending)

    const list = manager.testSubset
    const sortedList = type === 'duration' ? durationSort(list, ascending) : genericSort(list, type, ascending)
    manager.setRender(sortedList)
}

module.exports = {
    doInitSort,
    doSort,
}

},{"./datamanager.js":1,"./storage.js":8}],8:[function(require,module,exports){
const possibleFilters = [
    'passed',
    'skipped',
    'failed',
    'error',
    'xfailed',
    'xpassed',
    'rerun',
]

const getVisible = () => {
    const url = new URL(window.location.href)
    const settings = new URLSearchParams(url.search).get('visible')
    const lower = (item) => {
        const lowerItem = item.toLowerCase()
        if (possibleFilters.includes(lowerItem)) {
            return lowerItem
        }
        return null
    }
    return settings === null ?
        possibleFilters :
        [...new Set(settings?.split(',').map(lower).filter((item) => item))]
}

const hideCategory = (categoryToHide) => {
    const url = new URL(window.location.href)
    const visibleParams = new URLSearchParams(url.search).get('visible')
    const currentVisible = visibleParams ? visibleParams.split(',') : [...possibleFilters]
    const settings = [...new Set(currentVisible)].filter((f) => f !== categoryToHide).join(',')

    url.searchParams.set('visible', settings)
    window.history.pushState({}, null, unescape(url.href))
}

const showCategory = (categoryToShow) => {
    if (typeof window === 'undefined') {
        return
    }
    const url = new URL(window.location.href)
    const currentVisible = new URLSearchParams(url.search).get('visible')?.split(',').filter(Boolean) ||
        [...possibleFilters]
    const settings = [...new Set([categoryToShow, ...currentVisible])]
    const noFilter = possibleFilters.length === settings.length || !settings.length

    noFilter ? url.searchParams.delete('visible') : url.searchParams.set('visible', settings.join(','))
    window.history.pushState({}, null, unescape(url.href))
}

const getSort = (initialSort) => {
    const url = new URL(window.location.href)
    let sort = new URLSearchParams(url.search).get('sort')
    if (!sort) {
        sort = initialSort || 'result'
    }
    return sort
}

const setSort = (type) => {
    const url = new URL(window.location.href)
    url.searchParams.set('sort', type)
    window.history.pushState({}, null, unescape(url.href))
}

const getCollapsedCategory = (renderCollapsed) => {
    let categories
    if (typeof window !== 'undefined') {
        const url = new URL(window.location.href)
        const collapsedItems = new URLSearchParams(url.search).get('collapsed')
        switch (true) {
        case !renderCollapsed && collapsedItems === null:
            categories = ['passed']
            break
        case collapsedItems?.length === 0 || /^["']{2}$/.test(collapsedItems):
            categories = []
            break
        case /^all$/.test(collapsedItems) || collapsedItems === null && /^all$/.test(renderCollapsed):
            categories = [...possibleFilters]
            break
        default:
            categories = collapsedItems?.split(',').map((item) => item.toLowerCase()) || renderCollapsed
            break
        }
    } else {
        categories = []
    }
    return categories
}

const getSortDirection = () => JSON.parse(sessionStorage.getItem('sortAsc')) || false
const setSortDirection = (ascending) => sessionStorage.setItem('sortAsc', ascending)

const getCollapsedIds = () => JSON.parse(sessionStorage.getItem('collapsedIds')) || []
const setCollapsedIds = (list) => sessionStorage.setItem('collapsedIds', JSON.stringify(list))

module.exports = {
    getVisible,
    hideCategory,
    showCategory,
    getCollapsedIds,
    setCollapsedIds,
    getSort,
    setSort,
    getSortDirection,
    setSortDirection,
    getCollapsedCategory,
    possibleFilters,
}

},{}]},{},[4]);
    </script>
  </footer>
</html>